package io.kimmking.chatoom.server.handler;

import io.kimmking.chatoom.server.config.NettyServerConfig;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务端处理消息的Handler
 */
@Slf4j
@Component
public class NettyServerMsgHandler extends SimpleChannelInboundHandler<String> {

    /**
     * 此处为了实现私聊功能，保存用户和channel的对应关系，这里的key存储用户的唯一标识
     * todo 后期会使用redis进行存储
     */
    private static final Map<String, Channel> channelRelation = new HashMap<>();

    private static final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    /**
     * 处理接收到的消息
     * @param channelHandlerContext
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
        Channel channel = channelHandlerContext.channel();

        /**
         * 此处暂且作简单判断，如果消息里包含'#'表示是私聊
         */
        if (msg.contains("#")){
            String userId = msg.split("#")[0];
            String body = msg.split("#")[1];
            Channel userChannel = channelRelation.get(userId);

            String addr = channel.remoteAddress().toString();
            userChannel.writeAndFlush(sf.format(new Date()) + "\n 【用户】" + addr + "说 : " + body);
            return;
        }

        //群发模式,排除自己不发送
        NettyServerConfig.channelGroup.parallelStream()
                .filter(c -> channel != c)
                .forEach(c1 -> c1.writeAndFlush(sf.format(new Date()) + "\n 【用户】 " + c1.remoteAddress().toString() + " 说 : " + msg));
    }

    /**
     * 建立连接之后第一个调用的方法
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);

        Channel channel = ctx.channel();
        String addr = channel.remoteAddress().toString();

        channel.writeAndFlush(sf.format(new Date()) + "\n 【用户】 " +addr+ " 加入聊天室 ");
        NettyServerConfig.channelGroup.add(channel);
        channelRelation.put(addr, channel);
    }

    /**
     * channel连接状态就绪之后调用
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        String address = ctx.channel().remoteAddress().toString();
        log.info("{}\n 【用户】 {} 上线 ", sf.format(new Date()), address);
    }

    /**
     * channel连接状态断开后触发
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        String address = ctx.channel().remoteAddress().toString();
        log.info("{}\n 【用户】 {} 下线 ", sf.format(new Date()), address);

        channelRelation.remove(address);
    }

    /**
     * 连接发送异常时触发
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        String address = ctx.channel().remoteAddress().toString();
        log.error("{}\n 【用户】 {} 连接发送异常: {}", sf.format(new Date()), address, cause.getMessage());
        ctx.close();
    }

    /**
     * 连接断开时触发该消息
     * 同时channel也会自动地从ChannelGroup中被移除
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
        Channel channel = ctx.channel();

        channel.writeAndFlush(sf.format(new Date()) + "\n 【用户】 " +
                channel.remoteAddress().toString() + " 离开了 ");
        //服务端本地打印ChannelGroup当前的在线人数
        log.info("当前在线人数是: {}", NettyServerConfig.channelGroup.size());
    }
}
